package service

import (
	"database/sql"
	"errors"
	"fmt"
	"gin-epg/internal/app/dao"
	"gin-epg/internal/app/entity"
	"github.com/jinzhu/gorm"
	"strings"
	"time"
)

// HandleEpgProgramSyncCron 处理 EPG 节目同步，支持传入 beforeDay 和 afterDay 参数指定同步的天数范围
// HandleEpgProgramSyncCron 处理 EPG 节目同步，支持传入 beforeDay 和 afterDay 参数指定同步的天数范围
func HandleEpgProgramSyncCron(beforeDay, afterDay int) error {
	dao.Logger.Infof("handleEpgProgramSyncCron start with beforeDay: %d, afterDay: %d", beforeDay, afterDay)

	db := dao.SqlSession

	// 计算日期范围
	startDate := time.Now().AddDate(0, 0, -beforeDay).Format("2006-01-02")
	endDate := time.Now().AddDate(0, 0, afterDay).Format("2006-01-02")

	// 查询所有频道
	var channels []entity.EpgChannel
	if err := db.Find(&channels).Error; err != nil {
		return fmt.Errorf("failed to query epg_channels: %v", err)
	}

	for _, stdChannel := range channels {
		sources := splitSources(stdChannel.Source)

		for _, source := range sources {
			// 遍历日期范围
			currentDate := startDate
			for currentDate <= endDate {
				currentDateParsed, _ := time.Parse("2006-01-02", currentDate)

				// 检查是否有已存在的同步记录
				var existingSync entity.EpgProgramSync
				if err := db.Where(&entity.EpgProgramSync{Channel: stdChannel.Name, Date: entity.NullDate{sql.NullTime{Time: currentDateParsed, Valid: true}}}).First(&existingSync).Error; err != nil {
					if !errors.Is(err, gorm.ErrRecordNotFound) {
						dao.Logger.Warnf("failed to query existing sync record for channel %s on date %s: %v", stdChannel.Name, currentDate, err)
						currentDate = currentDateParsed.AddDate(0, 0, 1).Format("2006-01-02")
						continue
					}
					// 没有同步记录，继续处理
				} else {
					// 已经有同步记录，检查同步源是否相等
					if existingSync.Source != source {
						// 同步源不相等，跳过本次同步
						currentDate = currentDateParsed.AddDate(0, 0, 1).Format("2006-01-02")
						continue
					}

					// 查询当天的节目收集记录
					var programs []entity.EpgProgramCollect
					if err := db.Where(&entity.EpgProgramCollect{Channel: stdChannel.Name, Date: entity.NullDate{sql.NullTime{Time: currentDateParsed, Valid: true}}, Source: source}).Find(&programs).Error; err != nil {
						dao.Logger.Warnf("failed to query epg_program_collect for channel %s on date %s: %v", stdChannel.Name, currentDate, err)
						currentDate = currentDateParsed.AddDate(0, 0, 1).Format("2006-01-02")
						continue
					}

					// 查询已有的节目记录
					var existingPrograms []entity.EpgProgram
					if err := db.Where(&entity.EpgProgram{Channel: stdChannel.Name, Date: entity.NullDate{sql.NullTime{Time: currentDateParsed, Valid: true}}}).Find(&existingPrograms).Error; err != nil {
						dao.Logger.Warnf("failed to query existing programs for channel %s on date %s: %v", stdChannel.Name, currentDate, err)
						currentDate = currentDateParsed.AddDate(0, 0, 1).Format("2006-01-02")
						continue
					}

					// 比较节目数量
					if len(existingPrograms) != len(programs) {
						// 节目数量不相等，删除原有的同步记录
						if err := db.Delete(&existingSync).Error; err != nil {
							dao.Logger.Warnf("failed to delete sync record for channel %s on date %s: %v", stdChannel.Name, currentDate, err)
							currentDate = currentDateParsed.AddDate(0, 0, 1).Format("2006-01-02")
							continue
						}

						// 删除原有的节目记录
						if err := db.Where(&entity.EpgProgram{Channel: stdChannel.Name, Date: entity.NullDate{sql.NullTime{Time: currentDateParsed, Valid: true}}}).Delete(&entity.EpgProgram{}).Error; err != nil {
							dao.Logger.Warnf("failed to delete programs for channel %s on date %s: %v", stdChannel.Name, currentDate, err)
							currentDate = currentDateParsed.AddDate(0, 0, 1).Format("2006-01-02")
							continue
						}
					} else {
						// 节目数量相等，比较开始时间
						programsMap := make(map[string]entity.EpgProgramCollect)
						for _, program := range programs {
							programsMap[program.Start] = program
						}

						for _, existingProgram := range existingPrograms {
							if program, ok := programsMap[existingProgram.Start]; !ok || program.Start != existingProgram.Start {
								// 开始时间不一致，删除原有的同步记录
								if err := db.Delete(&existingSync).Error; err != nil {
									dao.Logger.Warnf("failed to delete sync record for channel %s on date %s: %v", stdChannel.Name, currentDate, err)
									currentDate = currentDateParsed.AddDate(0, 0, 1).Format("2006-01-02")
									continue
								}

								// 删除原有的节目记录
								if err := db.Where(&entity.EpgProgram{Channel: stdChannel.Name, Date: entity.NullDate{sql.NullTime{Time: currentDateParsed, Valid: true}}}).Delete(&entity.EpgProgram{}).Error; err != nil {
									dao.Logger.Warnf("failed to delete programs for channel %s on date %s: %v", stdChannel.Name, currentDate, err)
									currentDate = currentDateParsed.AddDate(0, 0, 1).Format("2006-01-02")
									continue
								}
								break
							} else {
								// 开始时间一致，比较结束时间
								if program.End != existingProgram.End {
									// 结束时间不一致，删除原有的同步记录
									if err := db.Delete(&existingSync).Error; err != nil {
										dao.Logger.Warnf("failed to delete sync record for channel %s on date %s: %v", stdChannel.Name, currentDate, err)
										currentDate = currentDateParsed.AddDate(0, 0, 1).Format("2006-01-02")
										continue
									}

									// 删除原有的节目记录
									if err := db.Where(&entity.EpgProgram{Channel: stdChannel.Name, Date: entity.NullDate{sql.NullTime{Time: currentDateParsed, Valid: true}}}).Delete(&entity.EpgProgram{}).Error; err != nil {
										dao.Logger.Warnf("failed to delete programs for channel %s on date %s: %v", stdChannel.Name, currentDate, err)
										currentDate = currentDateParsed.AddDate(0, 0, 1).Format("2006-01-02")
										continue
									}
									break
								}
							}
						}
					}

				}

				// 查询当天的节目收集记录
				var programs []entity.EpgProgramCollect
				if err := db.Where(&entity.EpgProgramCollect{Channel: stdChannel.Name, Date: entity.NullDate{sql.NullTime{Time: currentDateParsed, Valid: true}}, Source: source}).Find(&programs).Error; err != nil {
					dao.Logger.Warnf("failed to query epg_program_collect for channel %s on date %s: %v", stdChannel.Name, currentDate, err)
					currentDate = currentDateParsed.AddDate(0, 0, 1).Format("2006-01-02")
					continue
				}

				if len(programs) == 0 {
					currentDate = currentDateParsed.AddDate(0, 0, 1).Format("2006-01-02")
					continue
				}

				// 开始事务
				if err := db.Transaction(func(tx *gorm.DB) error {
					// 检查是否有已存在的同步记录
					var existingSync entity.EpgProgramSync
					if err := tx.Where(&entity.EpgProgramSync{Channel: stdChannel.Name, Date: entity.NullDate{sql.NullTime{Time: currentDateParsed, Valid: true}}}).First(&existingSync).Error; err != nil {
						if !errors.Is(err, gorm.ErrRecordNotFound) {
							dao.Logger.Warnf("failed to query existing sync record for channel %s on date %s: %v", stdChannel.Name, currentDate, err)
							return nil
						}
						// 没有同步记录，继续处理
						syncRecord := entity.EpgProgramSync{
							Channel:    stdChannel.Name,
							Date:       entity.NullDate{sql.NullTime{Time: currentDateParsed, Valid: true}},
							Source:     source,
							CreateTime: entity.NullTime{sql.NullTime{Time: time.Now(), Valid: true}},
						}
						if err := tx.Create(&syncRecord).Error; err != nil {
							dao.Logger.Warnf("failed to create sync record for channel %s on date %s: %v", stdChannel.Name, currentDate, err)
							return nil
						}
					} else {
						// 已经有同步记录，检查同步源是否相等
						if existingSync.Source != source {
							// 同步源不相等，跳过本次同步
							return nil
						}
					}

					for _, program := range programs {
						var existingProgram entity.EpgProgram
						if err := tx.Where(&entity.EpgProgram{Channel: program.Channel, Date: program.Date, Start: program.Start}).First(&existingProgram).Error; err != nil {
							if errors.Is(err, gorm.ErrRecordNotFound) {
								// 插入新记录
								newProgram := entity.EpgProgram{
									Channel:    program.Channel,
									Date:       program.Date,
									Start:      program.Start,
									End:        program.End,
									Title:      program.Title,
									Desc:       program.Desc,
									CreateTime: entity.NullTime{sql.NullTime{Time: time.Now(), Valid: true}},
								}
								if err := tx.Create(&newProgram).Error; err != nil {
									dao.Logger.Warnf("failed to insert program for channel %s on date %s: %v", stdChannel.Name, currentDate, err)
									continue
								}
							} else {
								dao.Logger.Warnf("failed to query existing program for channel %s on date %s: %v", stdChannel.Name, currentDate, err)
								continue
							}
						} else {
							// 更新现有记录
							if existingProgram.Title != program.Title || existingProgram.End != program.End || existingProgram.Desc != program.Desc {
								if err := tx.Model(&existingProgram).Updates(entity.EpgProgram{
									End:        program.End,
									Title:      program.Title,
									Desc:       program.Desc,
									UpdateTime: entity.NullTime{sql.NullTime{Time: time.Now(), Valid: true}},
								}).Error; err != nil {
									dao.Logger.Warnf("failed to update program for channel %s on date %s: %v", stdChannel.Name, currentDate, err)
									continue
								}
							}
						}
					}

					return nil
				}); err != nil {
					dao.Logger.Warnf("transaction failed for channel %s on date %s: %v", stdChannel.Name, currentDate, err)
				}

				dao.Logger.Infof("Sync completed for stdChannel: %s on date %s", stdChannel.Name, currentDate)
				currentDate = currentDateParsed.AddDate(0, 0, 1).Format("2006-01-02")
			}
		}
	}
	return nil
}

// splitSources 分割源字符串
func splitSources(s string) []string {
	return strings.Split(s, ",")
}

// deleteBefore7dayEpgProgram 删除 7 天前的 EPG 节目数据
func DeleteBefore7dayEpgProgram() error {
	db := dao.SqlSession
	const day = 6
	return deleteProgram(db, day)
}

// deleteBefore30dayEpgProgram 删除 30 天前的 EPG 节目数据
func DeleteBefore30dayEpgProgram() error {
	db := dao.SqlSession
	const day = 29
	return deleteProgram(db, day)
}

// deleteProgram 删除指定天数前的 EPG 节目数据
func deleteProgram(db *gorm.DB, day int) error {
	cutoffDate := time.Now().AddDate(0, 0, -day).Format("2006-01-02")

	// 删除节目表
	if err := db.Where("date < ?", cutoffDate).Delete(&entity.EpgProgram{}).Error; err != nil {
		dao.Logger.Warnf("Warning: failed to delete epg_program: %v\n", err)
		return err
	} else {
		dao.Logger.Infof("delete success: epg_program")
	}

	// 删除节目采集表
	if err := db.Where("date < ?", cutoffDate).Delete(&entity.EpgProgramCollect{}).Error; err != nil {
		dao.Logger.Warnf("Warning: failed to delete epg_program_collect: %v\n", err)
		return err
	} else {
		dao.Logger.Infof("delete success: epg_program_collect")
	}

	// 删除同步标志表
	if err := db.Where("date < ?", cutoffDate).Delete(&entity.EpgProgramSync{}).Error; err != nil {
		dao.Logger.Warnf("Warning: failed to delete epg_program_sync: %v\n", err)
		return err
	} else {
		dao.Logger.Infof("delete success: epg_program_sync")

	}

	return nil
}
